Skip to content

feat: validate eth_sendTransaction / eth_signTransaction params#9482

Open
OGPoyraz wants to merge 18 commits into
mainfrom
ogp/CONF-1662
Open

feat: validate eth_sendTransaction / eth_signTransaction params#9482
OGPoyraz wants to merge 18 commits into
mainfrom
ogp/CONF-1662

Conversation

@OGPoyraz

@OGPoyraz OGPoyraz commented Jul 13, 2026

Copy link
Copy Markdown
Member

Explanation

Malicious dapps can send eth_sendTransaction with a valid-looking payload plus a deeply-nested junk field (e.g. test.b.b.b... ~1200 levels). Downstream normalization in @metamask/transaction-controller recurses into these params and throws RangeError: Maximum call stack size exceeded. When this crash happens inside the extension/mobile PPOM middleware it short-circuits the security-scan pipeline: the request never reaches the Security Alerts API, and the user sees the confirmation without a Blockaid scan.

The same class of attack was fixed for eth_signTypedData_v4 in #8526 by rejecting requests with extraneous top-level keys. This PR applies the equivalent guardrail to transaction methods.

Changes

  • New validateTransactionParams(params) in src/utils/validation.ts, exported from the package. Rejects with rpcErrors.invalidInput() when:
    • params is not a plain object, or
    • contains a top-level key outside the dapp-facing subset of TransactionParams (accessList, authorizationList, chainId, data, from, gas, gasLimit, gasPrice, maxFeePerGas, maxPriorityFeePerGas, nonce, to, type, value), or
    • nests beyond depth 10 anywhere inside the params tree (legitimate params, including accessList / authorizationList, are ≤4 levels deep).
  • Wired into the eth_sendTransaction and eth_signTransaction handlers in createWalletMiddleware, before validateAndNormalizeKeyholder.
  • Also exported from index.ts so extension/mobile PPOM middleware can gate params before their own normalizeTransactionParams call (which is where the WASM crash actually originates in clients).

Design notes

  • Reject vs. strip: matches feat: adding more validations for types sign v4 messages #8526 — reject the whole request with invalidInput. Stripping silently would hide the attack pattern from telemetry.
  • Allowlist scope: intentionally omits internal-only fields on TransactionParams (estimateGasError, estimatedBaseFee, estimateSuggested, estimateUsed, gasUsed) — dapps should not be able to inject those.
  • Depth of 10: ~2-3× headroom over legitimate use. Change if any real dapp turns out to nest deeper.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

High Risk
Breaking RPC behavior on transaction methods at the wallet/security boundary; incorrect allowlisting or size limits could reject legitimate dapp traffic or leave attack paths open.

Overview
Adds breaking strict validation on eth_sendTransaction and eth_signTransaction so malicious or malformed transaction params are rejected before account checks and downstream normalization.

Introduces validateTransactionParams (exported from the package) with a Superstruct TransactionParamsStruct allowlist (from required; optional dapp-facing fields including accessList / authorizationList). Unknown top-level keys fail schema validation without traversing their values, blocking deeply nested junk that could crash PPOM/normalization and skip security scans. After schema checks, serialized size over MAX_TRANSACTION_PARAMS_SIZE_BYTES (200 KB) throws invalidInput.

Wallet middleware calls validation in both transaction handlers before validateAndNormalizeKeyholder. Changelog and unit/integration tests cover extraneous keys, wrong types, padding attacks, and end-to-end RPC rejection.

Reviewed by Cursor Bugbot for commit 2b91e13. Bugbot is set up for automated code reviews on this repo. Configure here.

} from './methods/wallet-get-supported-execution-permissions';
export * from './providerAsMiddleware';
export * from './retryOnEmpty';
export { validateTransactionParams } from './utils/validation';

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extension/mobile PPOM middleware can gate params before their own normalizeTransactionParams call (which is where the WASM crash actually originates in clients).

@OGPoyraz OGPoyraz marked this pull request as ready for review July 13, 2026 08:59
@OGPoyraz OGPoyraz requested review from a team as code owners July 13, 2026 08:59
@OGPoyraz OGPoyraz temporarily deployed to default-branch July 13, 2026 08:59 — with GitHub Actions Inactive
@OGPoyraz

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.5.5-preview-56569acf0
@metamask-previews/accounts-controller@39.0.5-preview-56569acf0
@metamask-previews/address-book-controller@7.1.2-preview-56569acf0
@metamask-previews/ai-controllers@0.8.0-preview-56569acf0
@metamask-previews/analytics-controller@1.2.1-preview-56569acf0
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-56569acf0
@metamask-previews/announcement-controller@8.1.0-preview-56569acf0
@metamask-previews/app-metadata-controller@2.0.1-preview-56569acf0
@metamask-previews/approval-controller@9.0.2-preview-56569acf0
@metamask-previews/assets-controller@10.2.1-preview-56569acf0
@metamask-previews/assets-controllers@109.4.1-preview-56569acf0
@metamask-previews/authenticated-user-storage@3.0.1-preview-56569acf0
@metamask-previews/base-controller@9.1.0-preview-56569acf0
@metamask-previews/base-data-service@0.1.3-preview-56569acf0
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-56569acf0
@metamask-previews/bridge-controller@77.4.1-preview-56569acf0
@metamask-previews/bridge-status-controller@74.1.2-preview-56569acf0
@metamask-previews/build-utils@3.0.4-preview-56569acf0
@metamask-previews/chain-agnostic-permission@1.7.0-preview-56569acf0
@metamask-previews/chomp-api-service@3.1.0-preview-56569acf0
@metamask-previews/claims-controller@0.5.3-preview-56569acf0
@metamask-previews/client-controller@1.0.1-preview-56569acf0
@metamask-previews/client-utils@1.1.0-preview-56569acf0
@metamask-previews/compliance-controller@2.1.0-preview-56569acf0
@metamask-previews/composable-controller@12.0.1-preview-56569acf0
@metamask-previews/config-registry-controller@0.4.1-preview-56569acf0
@metamask-previews/connectivity-controller@0.3.0-preview-56569acf0
@metamask-previews/controller-utils@12.3.0-preview-56569acf0
@metamask-previews/core-backend@6.5.0-preview-56569acf0
@metamask-previews/delegation-controller@3.0.2-preview-56569acf0
@metamask-previews/earn-controller@12.2.2-preview-56569acf0
@metamask-previews/eip-5792-middleware@3.0.5-preview-56569acf0
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-56569acf0
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-56569acf0
@metamask-previews/ens-controller@19.1.5-preview-56569acf0
@metamask-previews/eth-block-tracker@15.0.1-preview-56569acf0
@metamask-previews/eth-json-rpc-middleware@23.1.3-preview-56569acf0
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-56569acf0
@metamask-previews/foundryup@1.0.1-preview-56569acf0
@metamask-previews/gas-fee-controller@26.2.4-preview-56569acf0
@metamask-previews/gator-permissions-controller@4.2.3-preview-56569acf0
@metamask-previews/geolocation-controller@0.1.3-preview-56569acf0
@metamask-previews/java-tron-up@1.0.0-preview-56569acf0
@metamask-previews/json-rpc-engine@10.5.0-preview-56569acf0
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-56569acf0
@metamask-previews/keyring-controller@27.1.0-preview-56569acf0
@metamask-previews/local-node-utils@1.0.0-preview-56569acf0
@metamask-previews/logging-controller@8.0.2-preview-56569acf0
@metamask-previews/message-manager@14.1.2-preview-56569acf0
@metamask-previews/messenger@2.0.0-preview-56569acf0
@metamask-previews/messenger-cli@0.2.0-preview-56569acf0
@metamask-previews/money-account-api-data-service@0.1.0-preview-56569acf0
@metamask-previews/money-account-balance-service@2.2.0-preview-56569acf0
@metamask-previews/money-account-controller@0.3.3-preview-56569acf0
@metamask-previews/money-account-upgrade-controller@2.2.1-preview-56569acf0
@metamask-previews/multichain-account-service@13.0.0-preview-56569acf0
@metamask-previews/multichain-api-middleware@4.0.1-preview-56569acf0
@metamask-previews/multichain-network-controller@3.2.1-preview-56569acf0
@metamask-previews/multichain-transactions-controller@7.1.1-preview-56569acf0
@metamask-previews/name-controller@9.1.2-preview-56569acf0
@metamask-previews/network-connection-banner-controller@0.1.0-preview-56569acf0
@metamask-previews/network-controller@34.0.0-preview-56569acf0
@metamask-previews/network-enablement-controller@5.5.0-preview-56569acf0
@metamask-previews/notification-services-controller@25.0.0-preview-56569acf0
@metamask-previews/passkey-controller@2.0.1-preview-56569acf0
@metamask-previews/permission-controller@13.1.1-preview-56569acf0
@metamask-previews/permission-log-controller@5.1.0-preview-56569acf0
@metamask-previews/perps-controller@9.2.1-preview-56569acf0
@metamask-previews/phishing-controller@17.2.1-preview-56569acf0
@metamask-previews/platform-api-docs@0.0.0-preview-56569acf0
@metamask-previews/polling-controller@16.0.8-preview-56569acf0
@metamask-previews/preferences-controller@23.1.0-preview-56569acf0
@metamask-previews/profile-metrics-controller@4.0.2-preview-56569acf0
@metamask-previews/profile-sync-controller@28.3.0-preview-56569acf0
@metamask-previews/ramps-controller@16.0.0-preview-56569acf0
@metamask-previews/rate-limit-controller@7.0.1-preview-56569acf0
@metamask-previews/react-data-query@0.2.1-preview-56569acf0
@metamask-previews/remote-feature-flag-controller@4.2.2-preview-56569acf0
@metamask-previews/sample-controllers@5.0.3-preview-56569acf0
@metamask-previews/seedless-onboarding-controller@10.0.3-preview-56569acf0
@metamask-previews/selected-network-controller@26.1.5-preview-56569acf0
@metamask-previews/shield-controller@5.1.3-preview-56569acf0
@metamask-previews/signature-controller@39.2.7-preview-56569acf0
@metamask-previews/smart-transactions-controller@25.0.1-preview-56569acf0
@metamask-previews/snap-account-service@2.0.0-preview-56569acf0
@metamask-previews/social-controllers@2.4.0-preview-56569acf0
@metamask-previews/solana-test-validator-up@1.0.0-preview-56569acf0
@metamask-previews/stellar-quickstart-up@0.0.0-preview-56569acf0
@metamask-previews/storage-service@1.0.2-preview-56569acf0
@metamask-previews/subscription-controller@6.2.1-preview-56569acf0
@metamask-previews/transaction-controller@69.0.0-preview-56569acf0
@metamask-previews/transaction-pay-controller@24.0.3-preview-56569acf0
@metamask-previews/user-operation-controller@41.2.7-preview-56569acf0
@metamask-previews/wallet@7.0.1-preview-56569acf0
@metamask-previews/wallet-cli@0.0.0-preview-56569acf0

@matthewwalsh0 matthewwalsh0 requested a review from jpuri July 13, 2026 14:10
jpuri
jpuri previously approved these changes Jul 13, 2026
Comment thread packages/eth-json-rpc-middleware/src/utils/validation.ts
@OGPoyraz

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.5.5-preview-f9a776109
@metamask-previews/accounts-controller@39.0.5-preview-f9a776109
@metamask-previews/address-book-controller@7.1.2-preview-f9a776109
@metamask-previews/ai-controllers@0.8.0-preview-f9a776109
@metamask-previews/analytics-controller@1.2.1-preview-f9a776109
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-f9a776109
@metamask-previews/announcement-controller@8.1.0-preview-f9a776109
@metamask-previews/app-metadata-controller@2.0.1-preview-f9a776109
@metamask-previews/approval-controller@9.0.2-preview-f9a776109
@metamask-previews/assets-controller@10.2.1-preview-f9a776109
@metamask-previews/assets-controllers@109.4.1-preview-f9a776109
@metamask-previews/authenticated-user-storage@3.0.1-preview-f9a776109
@metamask-previews/base-controller@9.1.0-preview-f9a776109
@metamask-previews/base-data-service@0.1.3-preview-f9a776109
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-f9a776109
@metamask-previews/bridge-controller@77.4.1-preview-f9a776109
@metamask-previews/bridge-status-controller@74.1.2-preview-f9a776109
@metamask-previews/build-utils@3.0.4-preview-f9a776109
@metamask-previews/chain-agnostic-permission@1.7.0-preview-f9a776109
@metamask-previews/chomp-api-service@3.1.0-preview-f9a776109
@metamask-previews/claims-controller@0.5.3-preview-f9a776109
@metamask-previews/client-controller@1.0.1-preview-f9a776109
@metamask-previews/client-utils@1.1.0-preview-f9a776109
@metamask-previews/compliance-controller@2.1.0-preview-f9a776109
@metamask-previews/composable-controller@12.0.1-preview-f9a776109
@metamask-previews/config-registry-controller@0.4.1-preview-f9a776109
@metamask-previews/connectivity-controller@0.3.0-preview-f9a776109
@metamask-previews/controller-utils@12.3.0-preview-f9a776109
@metamask-previews/core-backend@6.5.0-preview-f9a776109
@metamask-previews/delegation-controller@3.0.2-preview-f9a776109
@metamask-previews/earn-controller@12.2.2-preview-f9a776109
@metamask-previews/eip-5792-middleware@3.0.5-preview-f9a776109
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-f9a776109
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-f9a776109
@metamask-previews/ens-controller@19.1.5-preview-f9a776109
@metamask-previews/eth-block-tracker@15.0.1-preview-f9a776109
@metamask-previews/eth-json-rpc-middleware@23.1.3-preview-f9a776109
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-f9a776109
@metamask-previews/foundryup@1.0.1-preview-f9a776109
@metamask-previews/gas-fee-controller@26.2.4-preview-f9a776109
@metamask-previews/gator-permissions-controller@4.2.3-preview-f9a776109
@metamask-previews/geolocation-controller@0.1.3-preview-f9a776109
@metamask-previews/java-tron-up@1.0.0-preview-f9a776109
@metamask-previews/json-rpc-engine@10.5.0-preview-f9a776109
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-f9a776109
@metamask-previews/keyring-controller@27.1.0-preview-f9a776109
@metamask-previews/local-node-utils@1.0.0-preview-f9a776109
@metamask-previews/logging-controller@8.0.2-preview-f9a776109
@metamask-previews/message-manager@14.1.2-preview-f9a776109
@metamask-previews/messenger@2.0.0-preview-f9a776109
@metamask-previews/messenger-cli@0.2.0-preview-f9a776109
@metamask-previews/money-account-api-data-service@0.1.0-preview-f9a776109
@metamask-previews/money-account-balance-service@2.2.0-preview-f9a776109
@metamask-previews/money-account-controller@0.3.3-preview-f9a776109
@metamask-previews/money-account-upgrade-controller@2.2.1-preview-f9a776109
@metamask-previews/multichain-account-service@13.0.0-preview-f9a776109
@metamask-previews/multichain-api-middleware@4.0.1-preview-f9a776109
@metamask-previews/multichain-network-controller@3.2.1-preview-f9a776109
@metamask-previews/multichain-transactions-controller@7.1.1-preview-f9a776109
@metamask-previews/name-controller@9.1.2-preview-f9a776109
@metamask-previews/network-connection-banner-controller@0.1.0-preview-f9a776109
@metamask-previews/network-controller@34.0.0-preview-f9a776109
@metamask-previews/network-enablement-controller@5.5.0-preview-f9a776109
@metamask-previews/notification-services-controller@25.0.0-preview-f9a776109
@metamask-previews/passkey-controller@2.0.1-preview-f9a776109
@metamask-previews/permission-controller@13.1.1-preview-f9a776109
@metamask-previews/permission-log-controller@5.1.0-preview-f9a776109
@metamask-previews/perps-controller@9.2.1-preview-f9a776109
@metamask-previews/phishing-controller@17.2.1-preview-f9a776109
@metamask-previews/platform-api-docs@0.0.0-preview-f9a776109
@metamask-previews/polling-controller@16.0.8-preview-f9a776109
@metamask-previews/preferences-controller@23.1.0-preview-f9a776109
@metamask-previews/profile-metrics-controller@4.0.2-preview-f9a776109
@metamask-previews/profile-sync-controller@28.3.0-preview-f9a776109
@metamask-previews/ramps-controller@16.0.0-preview-f9a776109
@metamask-previews/rate-limit-controller@7.0.1-preview-f9a776109
@metamask-previews/react-data-query@0.2.1-preview-f9a776109
@metamask-previews/remote-feature-flag-controller@4.2.2-preview-f9a776109
@metamask-previews/sample-controllers@5.0.3-preview-f9a776109
@metamask-previews/seedless-onboarding-controller@10.0.3-preview-f9a776109
@metamask-previews/selected-network-controller@26.1.5-preview-f9a776109
@metamask-previews/shield-controller@5.1.3-preview-f9a776109
@metamask-previews/signature-controller@39.2.7-preview-f9a776109
@metamask-previews/smart-transactions-controller@25.0.1-preview-f9a776109
@metamask-previews/snap-account-service@2.0.0-preview-f9a776109
@metamask-previews/social-controllers@2.4.0-preview-f9a776109
@metamask-previews/solana-test-validator-up@1.0.0-preview-f9a776109
@metamask-previews/stellar-quickstart-up@0.0.0-preview-f9a776109
@metamask-previews/storage-service@1.0.2-preview-f9a776109
@metamask-previews/subscription-controller@6.2.1-preview-f9a776109
@metamask-previews/transaction-controller@69.0.0-preview-f9a776109
@metamask-previews/transaction-pay-controller@24.0.3-preview-f9a776109
@metamask-previews/user-operation-controller@41.2.7-preview-f9a776109
@metamask-previews/wallet@7.0.1-preview-f9a776109
@metamask-previews/wallet-cli@0.0.0-preview-f9a776109

@OGPoyraz OGPoyraz requested a review from jpuri July 14, 2026 12:42
jpuri
jpuri previously approved these changes Jul 14, 2026
Comment thread packages/eth-json-rpc-middleware/src/wallet.test.ts Outdated
Comment thread packages/eth-json-rpc-middleware/src/wallet.test.ts Outdated
Comment thread packages/eth-json-rpc-middleware/CHANGELOG.md Outdated
Comment thread packages/eth-json-rpc-middleware/src/utils/validation.test.ts
Comment thread packages/eth-json-rpc-middleware/src/utils/validation.test.ts Outdated
Comment thread packages/eth-json-rpc-middleware/src/utils/validation.ts Outdated
throw rpcErrors.invalidInput();
}

validateParams(params, TransactionParamsStruct);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Struct validation before size cap

Medium Severity

validateTransactionParams now runs full Superstruct validation before the JSON.stringify size check. Oversized but schema-shaped payloads (e.g. padded accessList entries) previously failed on length alone; they now pay for per-entry struct validation first, weakening the intended cheap early rejection.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3009741. Configure here.

Comment thread packages/eth-json-rpc-middleware/src/utils/validation.ts
@OGPoyraz

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.5.5-preview-981855845
@metamask-previews/accounts-controller@39.0.5-preview-981855845
@metamask-previews/address-book-controller@7.1.2-preview-981855845
@metamask-previews/ai-controllers@0.8.0-preview-981855845
@metamask-previews/analytics-controller@1.2.1-preview-981855845
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-981855845
@metamask-previews/announcement-controller@8.1.0-preview-981855845
@metamask-previews/app-metadata-controller@2.0.1-preview-981855845
@metamask-previews/approval-controller@9.0.2-preview-981855845
@metamask-previews/assets-controller@10.2.1-preview-981855845
@metamask-previews/assets-controllers@109.4.1-preview-981855845
@metamask-previews/authenticated-user-storage@3.0.1-preview-981855845
@metamask-previews/base-controller@9.1.0-preview-981855845
@metamask-previews/base-data-service@0.1.3-preview-981855845
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-981855845
@metamask-previews/bridge-controller@77.4.1-preview-981855845
@metamask-previews/bridge-status-controller@74.1.2-preview-981855845
@metamask-previews/build-utils@3.0.4-preview-981855845
@metamask-previews/chain-agnostic-permission@1.7.0-preview-981855845
@metamask-previews/chomp-api-service@3.1.0-preview-981855845
@metamask-previews/claims-controller@0.5.3-preview-981855845
@metamask-previews/client-controller@1.0.1-preview-981855845
@metamask-previews/client-utils@1.1.0-preview-981855845
@metamask-previews/compliance-controller@2.1.0-preview-981855845
@metamask-previews/composable-controller@12.0.1-preview-981855845
@metamask-previews/config-registry-controller@0.4.1-preview-981855845
@metamask-previews/connectivity-controller@0.3.0-preview-981855845
@metamask-previews/controller-utils@12.3.0-preview-981855845
@metamask-previews/core-backend@6.5.0-preview-981855845
@metamask-previews/delegation-controller@3.0.2-preview-981855845
@metamask-previews/earn-controller@12.2.2-preview-981855845
@metamask-previews/eip-5792-middleware@3.0.5-preview-981855845
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-981855845
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-981855845
@metamask-previews/ens-controller@19.1.5-preview-981855845
@metamask-previews/eth-block-tracker@15.0.1-preview-981855845
@metamask-previews/eth-json-rpc-middleware@23.1.3-preview-981855845
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-981855845
@metamask-previews/foundryup@1.0.1-preview-981855845
@metamask-previews/gas-fee-controller@26.2.4-preview-981855845
@metamask-previews/gator-permissions-controller@4.2.3-preview-981855845
@metamask-previews/geolocation-controller@0.1.3-preview-981855845
@metamask-previews/java-tron-up@1.0.0-preview-981855845
@metamask-previews/json-rpc-engine@10.5.0-preview-981855845
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-981855845
@metamask-previews/keyring-controller@27.1.0-preview-981855845
@metamask-previews/local-node-utils@1.0.0-preview-981855845
@metamask-previews/logging-controller@8.0.2-preview-981855845
@metamask-previews/message-manager@14.1.2-preview-981855845
@metamask-previews/messenger@2.0.0-preview-981855845
@metamask-previews/messenger-cli@0.2.0-preview-981855845
@metamask-previews/money-account-api-data-service@0.1.0-preview-981855845
@metamask-previews/money-account-balance-service@2.2.0-preview-981855845
@metamask-previews/money-account-controller@0.3.3-preview-981855845
@metamask-previews/money-account-upgrade-controller@2.2.1-preview-981855845
@metamask-previews/multichain-account-service@13.0.0-preview-981855845
@metamask-previews/multichain-api-middleware@4.0.1-preview-981855845
@metamask-previews/multichain-network-controller@3.2.1-preview-981855845
@metamask-previews/multichain-transactions-controller@7.1.1-preview-981855845
@metamask-previews/name-controller@9.1.2-preview-981855845
@metamask-previews/network-connection-banner-controller@0.1.0-preview-981855845
@metamask-previews/network-controller@34.0.0-preview-981855845
@metamask-previews/network-enablement-controller@5.5.0-preview-981855845
@metamask-previews/notification-services-controller@25.0.0-preview-981855845
@metamask-previews/passkey-controller@2.0.1-preview-981855845
@metamask-previews/permission-controller@13.1.1-preview-981855845
@metamask-previews/permission-log-controller@5.1.0-preview-981855845
@metamask-previews/perps-controller@9.2.1-preview-981855845
@metamask-previews/phishing-controller@17.2.1-preview-981855845
@metamask-previews/platform-api-docs@0.0.0-preview-981855845
@metamask-previews/polling-controller@16.0.8-preview-981855845
@metamask-previews/preferences-controller@23.1.0-preview-981855845
@metamask-previews/profile-metrics-controller@4.0.2-preview-981855845
@metamask-previews/profile-sync-controller@28.3.0-preview-981855845
@metamask-previews/ramps-controller@16.0.0-preview-981855845
@metamask-previews/rate-limit-controller@7.0.1-preview-981855845
@metamask-previews/react-data-query@0.2.1-preview-981855845
@metamask-previews/remote-feature-flag-controller@4.2.2-preview-981855845
@metamask-previews/sample-controllers@5.0.3-preview-981855845
@metamask-previews/seedless-onboarding-controller@10.0.3-preview-981855845
@metamask-previews/selected-network-controller@26.1.5-preview-981855845
@metamask-previews/shield-controller@5.1.3-preview-981855845
@metamask-previews/signature-controller@39.2.7-preview-981855845
@metamask-previews/smart-transactions-controller@25.0.1-preview-981855845
@metamask-previews/snap-account-service@2.0.0-preview-981855845
@metamask-previews/social-controllers@2.4.0-preview-981855845
@metamask-previews/solana-test-validator-up@1.0.0-preview-981855845
@metamask-previews/stellar-quickstart-up@0.0.0-preview-981855845
@metamask-previews/storage-service@1.0.2-preview-981855845
@metamask-previews/subscription-controller@6.2.1-preview-981855845
@metamask-previews/transaction-controller@69.0.0-preview-981855845
@metamask-previews/transaction-pay-controller@24.0.3-preview-981855845
@metamask-previews/user-operation-controller@41.2.7-preview-981855845
@metamask-previews/wallet@7.0.1-preview-981855845
@metamask-previews/wallet-cli@0.0.0-preview-981855845

@mcmire mcmire left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, but I would like another review from my team just to be safe.

Ogulcan Poyraz and others added 7 commits July 15, 2026 14:05
…nTransaction params

Reject requests whose top-level params contain keys outside the
allowlisted transaction fields or nest beyond MAX_TRANSACTION_PARAM_DEPTH
(10). Prevents downstream normalization / PPOM WASM from crashing with
RangeError on deeply-nested junk fields and silently bypassing security
scans.

Mirrors the guardrail pattern introduced for eth_signTypedData_v4 in
#8526.

CONF-1662
*/
export function validateTransactionParams(params: unknown): void {
if (Array.isArray(params)) {
throw rpcErrors.invalidInput();

@FrederikBolding FrederikBolding Jul 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we use invalidParams elsewhere when parameters have an unexpected shape

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, we don't need this at all as we are validating vs TransactionParamsStruct so removed this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here, I wouldn't recommend we change any errors or messages at this stage if possible, since the validation we'd like to add is very limited.


validateParams(params, TransactionParamsStruct);

if (JSON.stringify(params).length > MAX_TRANSACTION_PARAMS_SIZE_BYTES) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (JSON.stringify(params).length > MAX_TRANSACTION_PARAMS_SIZE_BYTES) {
if (new TextEncoder().encode(JSON.stringify(params)).byteLength > MAX_TRANSACTION_PARAMS_SIZE_BYTES) {

Technically this is more accurate (and also what we use in getJsonSize from utils). Though it is slower on mobile 😞

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the ping changed this to use getJsonSize.
About performance concerns, I think this will be fine for benign requests as they are not massive.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getJsonSize has another performance penalty as it also validates that the input is JSON. We can skip that in this case. Maybe time to upstream: https://github.com/MetaMask/snaps/blob/a2ea600bc3cfa66a5e476fed4335d557c9cb2a4b/packages/snaps-utils/src/json.ts#L33-L37 😅

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied the suggestion 😅

* Checks run in this order to guarantee we never recurse into hostile
* subtrees:
*
* 1. Top-level shape: params must be a plain object whose top-level keys

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes a lot of sense to be more cautions about validation here. Not necessarily a blocker, but I wonder if we've done any benchmarking at the cost (especially on mobile) of running x number of regexes on mobile?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately we haven't done any benchmarking because no data on Mixpanel of average size of benign dApp requests.

One plan in our mind is to check Sentinel state logs for submitted transactions but it will take time and we want to implement this as soon as possible to stop attack vectors.

Comment on lines +254 to +255
accessList: optional(array(AccessListEntryStruct)),
authorizationList: optional(array(AuthorizationListEntryStruct)),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we size limit these, just to some reasonable cap that cannot be exceeded in practice?


const AccessListEntryStruct = object({
address: HexAddressStruct,
storageKeys: array(StrictHexStruct),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nonce: optional(StrictHexStruct),
to: optional(HexAddressStruct),
type: optional(StrictHexStruct),
value: optional(StrictHexStruct),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not have coercion somewhere on fields like value, gasPrice, gasLimit etc somewhere? I thought dapps could get away with passing in numbers as well 🤔

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, but with this PR we're only focused on the shape of the request and its size - we're not aiming to fully implement strict validations yet. More rules will likely follow in future work.

chainId: optional(StrictHexStruct),
data: optional(StrictHexStruct),
from: HexAddressStruct,
gas: optional(StrictHexStruct),

@matthewwalsh0 matthewwalsh0 Jul 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the confusion Goktug, I was suggesting we add a superstruct schema as a mechanism to define valid fields.

But I definitely would not recommend we add any additional validations in this PR, in the form of specific property types, as the scope of the change is specifically for total request size.

So should all these just be loose properties as they were before, at least for now?

So the only net change is the size validation?

@OGPoyraz OGPoyraz Jul 15, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But size check may not enough alone?

Attackers are can bloat the request with tiny addition of object extending like {"a":{"a":{"a":{"a".... and even small size of the request can still overwhelm PPOM. Hence I was thinking implementing loose validation of shape.

But if the intent was just implementing size validation, I am totally fine to remove all.

@matthewwalsh0 matthewwalsh0 Jul 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I think the schema is a good idea to define what fields are allowed, but I'd be nervous to define strict types for those fields in this PR, as the risk to dApps is big given normalization etc.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 42f0c85. Configure here.

Comment thread packages/eth-json-rpc-middleware/src/utils/validation.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants